package cn.funeralobjects.upms.service.impl;

import cn.funeralobjects.common.jpa.service.CommonCloudCrudJpaService;
import cn.funeralobjects.common.repository.CommonCloudRepository;
import cn.funeralobjects.common.service.annotataion.CommonRollback;
import cn.funeralobjects.common.service.annotataion.CommonService;
import cn.funeralobjects.common.service.exception.DataConflictException;
import cn.funeralobjects.common.service.validate.DataCheck;
import cn.funeralobjects.upms.BasicInfo;
import cn.funeralobjects.upms.entity.ERole;
import cn.funeralobjects.upms.entity.ERoleTag;
import cn.funeralobjects.upms.model.Role;
import cn.funeralobjects.upms.repository.RoleRepository;
import cn.funeralobjects.upms.repository.RoleTagRepository;
import cn.funeralobjects.upms.service.RoleService;
import cn.funeralobjects.util.Assert;
import cn.funeralobjects.util.annotation.ArgHasLength;
import cn.funeralobjects.util.annotation.ArgNotZero;
import cn.funeralobjects.util.annotation.AssertArg;
import org.springframework.data.repository.CrudRepository;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Optional;

/**
 * RoleService的实现类
 *
 * @author FuneralObjects
 * Create date: 2020/4/21 4:59 PM
 */
@CommonService
public class RoleServiceImpl implements RoleService, CommonCloudCrudJpaService<Role, ERole, Integer> {

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private RoleTagRepository roleTagRepository;

    private ERole Anonymous;

    @PostConstruct
    private void init() {
        Anonymous = this.findByCode(BasicInfo.ANONYMOUS_ROLE_CODE)
                .orElseGet(() -> this.add(new Role().setCode(BasicInfo.ANONYMOUS_ROLE_CODE).setName(BasicInfo.ANONYMOUS_ROLE_NAME)));
    }

    @CommonRollback
    @AssertArg
    @Override
    public void addRoleTag(Integer roleId, @ArgHasLength String tag) {
        mustExistsById(roleId);
        roleTagRepository.save(new ERoleTag().setRoleId(roleId).setTag(tag));
    }

    @CommonRollback
    @AssertArg
    @Override
    public void removeRoleTag(@ArgNotZero Integer roleId, @ArgHasLength String tag) {
        roleTagRepository.delete(new ERoleTag().setRoleId(roleId).setTag(tag));
    }

    @AssertArg
    @Override
    public Optional<ERole> findByRoleName(@ArgHasLength String roleName) {
        return roleRepository.findFirstByNameAndDelSalt(roleName, getExistsDelSalt());
    }

    @CommonRollback
    @AssertArg
    @Override
    public void updateRole(@ArgHasLength String name, @ArgNotZero Integer id) {
        mustExistsById(id);
        mustNotConflict(name, id);
        roleRepository.updateNameByIdAndDelSalt(name, id, getExistsDelSalt());
    }

    @Override
    public void mustNotConflict(String name) {
        DataCheck.conflictData(roleRepository.existsByNameAndDelSalt(name, getExistsDelSalt()),
                () -> createDataCode("name", name));
    }

    @Override
    public void mustNotConflict(String name, Integer withoutId) {
        DataCheck.conflictData(roleRepository.existsByNameAndIdNotAndDelSalt(name, withoutId, getExistsDelSalt()),
                () -> createDataCode("name", name));
    }

    @Override
    public String getName() {
        return ENTITY_NAME;
    }

    @Override
    public String getModuleName() {
        return BasicInfo.MODULE;
    }

    @Override
    public ERole getAnonymousRole() {
        return Anonymous;
    }

    private Integer getExistsDelSalt() {
        return (Integer) roleRepository.getDefaultExistsDelSalt();
    }

    @Override
    public CommonCloudRepository<ERole, Integer> commonCloudRepository() {
        return roleRepository;
    }


    @Override
    public void checkConflict(Role role) throws DataConflictException {
        validateModify(role);
        mustNotConflict(role.getName());
    }

    @Override
    public ERole toEntity(Role role) {
        return Optional.ofNullable(role)
                .map(r -> {
                    ERole entity = new ERole();
                    entity.setCode(role.getCode());
                    entity.setName(role.getName());
                    return entity;
                }).orElse(null);
    }

    @Override
    public CrudRepository<ERole, Integer> modifyRepository() {
        return roleRepository;
    }

    @Override
    public void checkConflict(Role role, Integer withoutId) throws DataConflictException {
        validateModify(role);
        mustNotConflict(role.getName(), withoutId);
    }

    @Override
    public void copyToEntity(Role sourceModify, ERole targetEntity) {
        targetEntity.setName(sourceModify.getName())
                .setCode(sourceModify.getCode());
    }

    @Override
    public void validateModify(Role role) {
        Assert.argAssert(role, "role");
    }
}
